import asyncio
import os
import random
from pathlib import Path

import httpx
import requests
from PIL import Image

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
    "Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3",
    "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0",
    "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.56",
    "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36",
]


def random_headers():
    return {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,"
        "application/signed-exchange;v=b3;q=0.9",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "Cache-Control": "max-age=0",
        "Connection": "keep-alive",
        "Upgrade-Insecure-Requests": "1",
        "User-Agent": random.choice(USER_AGENTS),
    }


def legalize(string: str):
    """To make a string won't cause any trouble"""
    string = string.replace("/", " ")
    string = string.replace("\\", " ")
    string = string.replace("<", "(")
    string = string.replace(">", ")")
    string = string.replace("?", "")
    string = string.replace("*", "")
    string = string.replace(":", " ")
    string = string.replace("|", " ")
    string = string.replace('"', "")
    return string


def replace_urls(urls: dict):
    for key in urls.keys():
        urls[key] = urls[key].replace("cat", "re")
    return urls


class Pic:
    def __init__(self, pic_data: dict):
        self.raw_data = pic_data

        self.pid: int = pic_data["pid"]
        self.uid: int = pic_data["uid"]
        self.ext: str = pic_data["ext"]
        self.p: int = pic_data["p"]
        self.title: str = pic_data["title"]
        self.filepath = Path(legalize(f"{self.title}_{self.pid}_p{self.p}.{self.ext}"))

        self.urls: dict = replace_urls(pic_data["urls"])
        self.url: str = self.urls["regular"]

        self.author: str = pic_data["author"]
        self.r18: bool = pic_data["r18"]
        self.tags: list = pic_data["tags"]

    def __eq__(self, o: object) -> bool:
        return self.pid == o.pid

    def __str__(self):
        return str(self.raw_data)

    def to_dict(self):
        data = self.raw_data
        data["url"] = self.url
        data["filepath"] = str(self.filepath)
        return data

    def remove(self):
        if self.filepath.is_file():
            os.remove(self.filepath)
            return True
        else:
            return False

    def show(self):
        if not self.filepath.is_file():
            raise FileNotFoundError(f"file {self.filepath} not found")

        img = Image.open(self.filepath)
        img.show()

    async def _download(self):
        async with httpx.AsyncClient() as client:
            response = await client.get(self.url, timeout=50, headers=random_headers())
            with open(self.filepath, mode="ab") as pic_file:
                pic_file.write(response.content)

    def download(self):
        response = requests.get(self.url, headers=random_headers())
        with open(self.filepath, mode="ab") as pic_file:
            pic_file.write(response.content)


class Pics:
    def __init__(self, num=5, r18=0, keyword=None, tag=None, uid=None):
        URL = "https://api.lolicon.app/setu/v2"
        params = {
            "r18": r18,
            "num": num,
            "size": ["original", "regular", "small", "mini"],
        }

        if tag is not None:
            params["tag"] = tag
        if uid:
            params["uid"] = uid
        if keyword:
            params["keyword"] = keyword

        response = requests.get(URL, params).json()

        self.err_msg: str = response["error"]
        if self.err_msg:
            raise requests.exceptions.ConnectionError(f"Error msg: {self.err_msg}")

        self.raw_datas: list = response["data"]

    def to_list(self):
        def to_dict(pic: Pic):
            return pic.to_dict()

        return list(map(to_dict, self.get_pics()))

    def get_pics(self):
        for pic_data in self.raw_datas:
            yield Pic(pic_data)

    def __len__(self):
        return len(self.raw_datas)

    async def _downloads(self):
        tasks = []
        for pic in self.get_pics():
            task = asyncio.create_task(pic._download())
            tasks.append(task)
        await asyncio.gather(*tasks)

    def download_all(self):
        asyncio.run(self._downloads())

    def __str__(self):
        return str(self.raw_datas)


if __name__ == "__main__":
    from pprint import pprint

    pics = Pics()

    pprint(pics.to_list())
    # pics.download_all()
